package com.cnbot.camera;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * Copyright (c) 2016--2019/3/25  Hunan Cnbot Co., Ltd. All Rights Reserved.
 *
 * @descriptoin 摄像头后台封装类
 * @FileName: BaseCameraService2.java
 * @author: wzz
 * @date: 2019/3/25 15:40
 * @version: 1.0
 */

public abstract class BaseCameraService2 extends Service {


    private static final String TAG = "BaseCameraService";

    private SurfaceView mSurfaceView;

    private Camera mCamera;

    /**
     * 是否正在进行人脸识别,默认关闭
     */
    private volatile boolean isRecognizing;
    /**
     * 是否开启了预览，默认关闭
     */
    private volatile boolean isPreviewing;
    private volatile byte[] cameraData;

    private Handler mPreviewHandler;
    private HandlerThread mPreviewThread;

    @Override
    public void onCreate() {
        //设置后台人脸识别的区域
        makeAndAddSurfaceView();
        initThread();
    }

    private void initThread() {
        if (mPreviewThread == null) {
            mPreviewThread = new HandlerThread("CameraService2");
            mPreviewThread.start();
            mPreviewHandler = new Handler(mPreviewThread.getLooper());
        }
    }

    private void quitThread() {
        if (mPreviewThread != null) {
            mPreviewThread.quit();
            mPreviewThread = null;
            mPreviewHandler = null;
        }
    }


    /**
     * 设置后台人脸识别的区域
     */
    private void makeAndAddSurfaceView() {
        //创建SurfaceView
        SurfaceView surfaceView = createSurfaceView();

        //将SurfaceView添加到窗口，指定宽高为1个像素，设置视图在所有Activity之上，不可获得焦点、不可触摸，全透明
        WindowManager.LayoutParams params = initWindowParams();
        //将SurfaceView添加到窗口
        addSurfaceView(surfaceView, params);

        mSurfaceView = surfaceView;
    }

    /**
     * 将SurfaceView添加到窗口
     *
     * @param surfaceView
     * @param params
     */
    private void addSurfaceView(SurfaceView surfaceView, WindowManager.LayoutParams params) {
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowManager.addView(surfaceView, params);
    }

    /**
     * 将SurfaceView添加到窗口，指定宽高为1个像素，
     * 设置视图在所有Activity之上，
     * 设置不可获得焦点、不可触摸，全透明
     *
     * @return
     */
    @NonNull
    private WindowManager.LayoutParams initWindowParams() {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(1, 1, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSPARENT);
        params.gravity = Gravity.TOP | Gravity.RIGHT;
        params.alpha = PixelFormat.TRANSPARENT;

        params.x = params.y = 1;
        return params;
    }

    /**
     * 创建SurfaceView
     *
     * @return
     */
    @NonNull
    private SurfaceView createSurfaceView() {
        SurfaceView surfaceView = new SurfaceView(this.getApplicationContext());
        surfaceView.setAlpha(0);
        surfaceView.getHolder().addCallback(mSurfaceHolderCallback);
        return surfaceView;
    }

    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.v(TAG, "surfaceCreated");
            initCamera();

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            Log.v(TAG, "surfaceChanged");
            startPreview(holder);

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.v(TAG, "surfaceDestroyed");
            closeCamera();
        }
    };

    /**
     * 摄像头打开失败，子类可重写监听
     *
     * @param message
     */
    protected void onCameraError(String message) {

    }

    /**
     * 开始预览
     *
     * @param holder
     * @throws IOException
     */
    private void startPreview(SurfaceHolder holder) {
        if (mCamera == null) {
            return;
        }
        // ww 初步断定是摄像头占用问题
        Camera.Parameters params = null;
        try {
            params = mCamera.getParameters();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
            onCameraError(ex.getMessage());
        }
        if (params == null) {
            return;
        }
        //预览的图片格式NV21（YUV420sp）
        //		int format = setPreviewFormat(params);
        //支持的成像帧率
        int[] range = setPreviewFpsRange(params);
        //设置预览的尺寸
        int[] size = setPreviewSize(params);
        //设置聚焦模式
        String mode = setFocusMode(params);

        //设置参数
        setCameraParameters(params);
        //打印配置参数信息
        Log.v(TAG, "Camera properties: " + "size=" + size[0] + "x" + size[1] + "; frameRates=" + range[0] + "-" + range[1] + ",focusMode=" + mode);
        startPreviewInternal(holder, size);
    }

    private void startPreviewInternal(SurfaceHolder holder, int[] size) {
        if (mCamera == null) {
            return;
        }
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
            onCameraError(e.getMessage());
            return;
        }
        //Callback buffer was too small! Expected 1382400 bytes, but got 460800 bytes!
        final int len = size[0] * size[1] * 3 / 2;
        Log.i(TAG, "startPreviewInternal: " + size[0] + "*" + size[1]);
        cameraData = new byte[len];
        mCamera.addCallbackBuffer(new byte[len]);
        //用于一个Camera复制多份数据在其他界面预览
        mCamera.setPreviewCallbackWithBuffer(mJpegPreviewCallback);
        try {
            mCamera.startPreview();
            //打开预览开关
            enablePreview();
        } catch (RuntimeException e) {
            e.printStackTrace();
            onCameraError(e.getMessage());
        }
    }

    private String setFocusMode(Camera.Parameters params) {
        String mode = getFocusMode(params.getSupportedFocusModes());
        if (!TextUtils.isEmpty(mode)) {
            params.setFocusMode(mode);
        }
        return mode;
    }

    /**
     * 子类可指定聚焦模式
     *
     * @param supportedFlashModes
     * @return
     */
    protected String getFocusMode(List<String> supportedFlashModes) {
        String mode = "";
        if (supportedFlashModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            mode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
        } else if (supportedFlashModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            mode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
        } else if (supportedFlashModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            mode = Camera.Parameters.FOCUS_MODE_AUTO;
        }
        return mode;
    }

    /**
     * 设置预览输出格式
     *
     * @return
     */
    private int setPreviewFormat(Camera.Parameters params) {
        int format = getPreviewFormat();
        params.setPreviewFormat(format);
        return format;
    }

    /**
     * 设置预览输出格式
     *
     * @return
     */
    protected int getPreviewFormat() {
        return ImageFormat.NV21;
    }

    /**
     * 设置摄像头参数
     *
     * @param params
     */
    private void setCameraParameters(Camera.Parameters params) {
        try {
            mCamera.setParameters(params);
        } catch (Exception e) {
            // 得到摄像头的参数
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPictureSize(1280, 720);
            parameters.setPreviewSize(1280, 720);
            mCamera.setParameters(parameters);
        }
    }

    /**
     * 根据摄像头支持的预览尺寸列表，设置默认的预览尺寸
     *
     * @param params
     */
    private int[] setPreviewSize(Camera.Parameters params) {
        int[] size = getPreviewSize(params.getSupportedPreviewSizes());
        params.setPreviewSize(size[0], size[1]);
        return size;
    }

    /**
     * 根据摄像头支持的预览尺寸列表，设置预览尺寸
     *
     * @param size
     */
    public void resetParameters(int[] size, String focusMode) {
        if (mCamera == null) {
            return;
        }
        mCamera.setPreviewCallbackWithBuffer(null);
        mCamera.stopPreview();
        Camera.Parameters params = null;
        try {
            params = mCamera.getParameters();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
            onCameraError(ex.getMessage());
        }
        if (params == null) {
            return;
        }
        //支持的成像帧率
        setPreviewFpsRange(params);
        //设置预览的尺寸
        params.setPreviewSize(size[0], size[1]);
        //设置聚焦模式
        params.setFocusMode(focusMode);

        //设置参数
        setCameraParameters(params);
        //打印配置参数信息
        startPreviewInternal(mSurfaceView.getHolder(), size);
    }

    /**
     * 根据摄像头支持的预览尺寸列表，设置默认的预览尺寸640*480
     * 子类可重写
     *
     * @param preSizes
     */
    protected int[] getPreviewSize(List<Camera.Size> preSizes) {

        return new int[]{1280, 720};
    }

    /**
     * 根据支持的成像帧率，指定当前的范围
     *
     * @param params
     * @return
     */
    private int[] setPreviewFpsRange(Camera.Parameters params) {
        int[] range = getPreviewFpsRange(params.getSupportedPreviewFpsRange());
        params.setPreviewFpsRange(range[0], range[1]);
        return range;
    }

    /**
     * 根据支持的成像帧率，默认指定第一个数组为当前的范围
     * 子类可重写根据需要重写指定
     *
     * @param frameRates
     * @return
     */
    protected int[] getPreviewFpsRange(List<int[]> frameRates) {
        int[] fps = new int[2];
        Iterator var6 = frameRates.iterator();

        while (var6.hasNext()) {
            int[] intArr = (int[]) var6.next();
            if (fps[0] == 0) {
                fps[0] = intArr[0];
                fps[1] = intArr[1];
            } else if (intArr[1] <= 30000 && intArr[0] >= fps[0] && intArr[1] >= fps[1]) {
                fps[0] = intArr[0];
                fps[1] = intArr[1];
            }
        }
        return fps;
    }

    protected Camera.Size getPreviewSize(List<Camera.Size> preSizes, int width) {
        sortPreSize(preSizes);

        for (Camera.Size s : preSizes) {
            if ((s.width >= width) && equalRate(s, 1.33f)) {
                return s;
            }
        }

        return null;
    }

    public boolean equalRate(Camera.Size s, float rate) {
        float r = (float) (s.width) / (float) (s.height);
        return Math.abs(r - rate) <= 0.2;

    }

    /**
     * 排序
     *
     * @param pres
     */
    protected void sortPreSize(List<Camera.Size> pres) {

        int min = 0;
        Camera.Size temp;
        for (int i = 0; i < pres.size() - 1; i++) {
            min = i;
            for (int j = i + 1; j < pres.size(); j++) {
                if (pres.get(j).width < pres.get(min).width) {
                    min = j;
                }
            }
            if (min != i) {
                temp = pres.get(min);
                pres.set(min, pres.get(i));
                pres.set(i, temp);
            }
        }

    }

    /**
     * 预览数据的回调
     */
    private final Camera.PreviewCallback mJpegPreviewCallback = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            if (data == null || camera == null) {
                return;
            }

            System.arraycopy(data, 0, cameraData, 0, data.length);
//            mPreviewHandler.post(mPreviewTask);
            updatePreviewListeners(mCamera);
            Log.i(TAG, "onPreviewFrame: 刷新图像" + data.length);
            camera.addCallbackBuffer(data);
        }
    };

    private final Runnable mPreviewTask = new Runnable() {
        //        private byte[] yuvData = new byte[1280 * 720 * 3 / 2];
        @Override
        public void run() {

            updatePreviewListeners(mCamera);

        }
    };

    private void updatePreviewListeners(Camera camera) {
        if (mPreviewListeners.size() > 0) {
            for (ICameraPreviewListener listener : mPreviewListeners) {
                listener.onPreviewFrame(cameraData, camera);
            }
        }
        Log.i(TAG, "updatePreviewListeners: 图像处理完毕");
    }

    private void initCamera() {
        if (mCamera == null) {
            try {
                mCamera = Camera.open(getCameraId());
            } catch (RuntimeException e) {
                Log.e(TAG, "the camera is in use by another process or device policy manager has disabled the camera");
                onCameraError(e.getMessage());
            }
        }
    }

    /**
     * 设置要打开的摄像头id
     * 由于不确定当前的设备是支持前置还是后置所以必须重写指定
     *
     * @return
     */
    public abstract int getCameraId();


    protected void removeListener() {
        mPreviewListeners.clear();
    }

    protected boolean removePreviewListener(ICameraPreviewListener l) {
        if (mPreviewListeners.size() > 0) {
            return mPreviewListeners.remove(l);
        }
        return false;
    }


    private final List<ICameraPreviewListener> mPreviewListeners = new ArrayList<>();

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");

        return new CameraBinderImpl2(this);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind");
        return true;
    }

    @Override
    public void onRebind(Intent intent) {
        Log.d(TAG, "onRebind");
    }


    /**
     * 重新初始化摄像头并启动人脸识别
     */
    protected void startRecognize() {
        if (!isPreviewing()) {
            Log.w(TAG, "camera preview is false");
            return;
        }
        Log.d(TAG, "startRecognize");
    }


    /**
     * 开启预览
     */
    private void enablePreview() {
        isPreviewing = true;
    }

    /**
     * 关闭预览
     */
    private void disablePreview() {

        isPreviewing = false;

    }

    /**
     * 是否开启了预览
     *
     * @return
     */
    protected boolean isPreviewing() {
        return isPreviewing;
    }

    /**
     * 重新初始化摄像头并启动人脸识别
     */
    protected void openCamera() {
        initCamera();
        startPreview(mSurfaceView.getHolder());
        Log.d(TAG, "openCamera");
    }

    /**
     * 释放相机资源
     */
    public void closeCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallbackWithBuffer(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
            disablePreview();
            Log.d(TAG, "closeCamera");
        }

    }

    @Override
    public void onDestroy() {
        quitThread();
        closeCamera();
        Log.d(TAG, "摄像头服务退出");
        super.onDestroy();
    }

    protected void addCameraPreviewListener(ICameraPreviewListener l) {
        if (!mPreviewListeners.contains(l)) {
            mPreviewListeners.add(l);
        }
    }


    private Camera.CameraInfo getCameraInfo() {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        try {
            Camera.getCameraInfo(getCameraId(), cameraInfo);

        } catch (RuntimeException e) {
            Log.e(TAG, "camera is error please check and restart");
        }
        return cameraInfo;
    }

    /**
     * 是否是手持设备，设备是否支持旋转
     * 默认用于机器人属于固定横屏，不支持旋转
     *
     * @return
     */
    protected boolean isHandlerDevice() {
        return false;
    }


    public int normalizationRotate(int rotate) {
        while (rotate < 0) {
            rotate += 360;
        }
        return (rotate % 360);
    }

}
